﻿namespace DependencyPropertyChangedSample.Behaviors
{
    using System;
    using System.Collections.Generic;
    using System.Windows;
    using System.Windows.Input;
    using System.Windows.Interactivity;
    using System.Windows.Media.Animation;
    using DependencyPropertyChangedSample.Extensions;

    public class DragFlickBehavior : Behavior<FrameworkElement>
    {
        private FrameworkElement[] _elementsToAnimate;
        
        protected override void OnAttached()
        {
            base.OnAttached();
            AssociatedObject.Loaded += AssociatedObjectLoaded;
            AssociatedObject.ManipulationDelta += AssociatedObjectManipulationDelta;
            AssociatedObject.ManipulationCompleted += AssociatedObjectManipulationCompleted;
        }
        
        void AssociatedObjectLoaded(object sender, RoutedEventArgs e)
        {
            Load();
 
        }

        public void Load()
        {
            var elementList = new List<FrameworkElement>();
            foreach (var item in TargetControls)
            {
                if (item == null) continue;

                FrameworkElement element;

                if (AssociatedObject.Name == item)
                    element = AssociatedObject;
                else
                    element = (AssociatedObject.FindName(item) as FrameworkElement);
                
                if (element == null) continue;

                elementList.Add(element);
            }

            _elementsToAnimate = elementList.ToArray();

            
        }

        void AssociatedObjectManipulationDelta(object sender, ManipulationDeltaEventArgs e)
        {
            e.Handled = true;

            var dx = e.DeltaManipulation.Translation.X;
            var dy = e.DeltaManipulation.Translation.Y;
            foreach (var _elementToAnimate in _elementsToAnimate)
            {
                var currentPosition = _elementToAnimate.GetCanvasPoint();
                _elementToAnimate.SetCanvasPoint(currentPosition.X + dx, currentPosition.Y + dy);
            }
   

        }

        private void AssociatedObjectManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
        {

            foreach (var _elementToAnimate in _elementsToAnimate)
            {
                var currentPosition = _elementToAnimate.GetCanvasPoint();
                var velocity = e.FinalVelocities.LinearVelocity;
                var storyboard = new Storyboard { FillBehavior = FillBehavior.HoldEnd };

                var to = new Point(currentPosition.X + (velocity.X / BrakeSpeed),
                    currentPosition.Y + (velocity.Y / BrakeSpeed));

                storyboard.AddTranslationAnimation(_elementToAnimate, currentPosition, to,
                    new Duration(TimeSpan.FromMilliseconds(500)),
                    new CubicEase { EasingMode = EasingMode.EaseOut });

                storyboard.Begin();
            }
        }


        protected override void OnDetaching()
        {
            AssociatedObject.Loaded -= AssociatedObjectLoaded;
            AssociatedObject.ManipulationCompleted -= AssociatedObjectManipulationCompleted;
            AssociatedObject.ManipulationDelta-= AssociatedObjectManipulationDelta;

            base.OnDetaching();
        }

        #region BrakeSpeed
        public const string BrakeSpeedPropertyName = "BrakeSpeed";

        /// <summary>
        /// Describes how fast the element should brake, i.e. come to rest,
        /// after a flick. Higher = apply more brake ;-)
        /// </summary>
        public int BrakeSpeed
        {
            get { return (int)GetValue(BrakeSpeedProperty); }
            set { SetValue(BrakeSpeedProperty, value); }
        }

        public static readonly DependencyProperty BrakeSpeedProperty = DependencyProperty.Register(
            BrakeSpeedPropertyName,
            typeof(int),
            typeof(DragFlickBehavior),
            new PropertyMetadata(10));

        #endregion

        #region TargetControls


        public List<String> TargetControls
        {
            get
            {
                if (GetValue(TargetControlsProperty) == null) 
                    TargetControls = new List<string>();

                return (List<String>)GetValue(TargetControlsProperty); 
            
            }
            set { SetValue(TargetControlsProperty, value); }
        }

        public static readonly DependencyProperty TargetControlsProperty = DependencyProperty.Register("TargetControls", typeof(List<String>), typeof(DragFlickBehavior), new PropertyMetadata(null));

        
        #endregion
    }
}
